local envs = {}
	local entities = ents.FindByClass( "Environment" )
	for _, ent in ipairs( entities ) do
		local radius = ent:GetSize()
		table.insert(envs, {['ent'] = ent, ['rad'] = radius})
		print("Added a planet to the Gravity list with a radius of"..radius)
	end
						
CreateConVar( "sb_gravmul", "0.0006", FCVAR_NOTIFY )
CreateConVar( "sb_rad", 4000, FCVAR_NOTIFY )
CreateConVar( "sb_updatera", "0.5", FCVAR_NOTIFY )
CreateConVar( "sb_affectnoclip", "0", FCVAR_NOTIFY )
CreateConVar( "sb_disablegrav", "1", FCVAR_NOTIFY )

--[[tehaffect = {
	"player",
	"prop_physics",
	"prop_ragdoll",
	"npc_grenade_frag",
	"npc_grenade_bugbait",
	"npc_satchel",
	"grenade_ar2",
	"crossbow_bolt",
	"phys_magnet",
	"prop_vehicle_airboat",
	"prop_vehicle_jeep",
	"prop_vehicle_prisoner_pod"
}]]



--[[
function throwit(ent)
	mult = tostring(GetConVarNumber("sb_gravmul"))
	raid = tostring(GetConVarNumber("sb_rad"))
	nonoclip = tostring(GetConVarNumber("sb_affectnoclip"))
	nograv = tostring(GetConVarNumber("sb_disablegrav"))
	if not ent:IsValid() 
	or not ent:GetPhysicsObject():IsValid() 
	or ent:GetPhysicsObject():IsAsleep()
	 
	then return end
	local pos = ent:GetPos()
	local onplanet, num = SB_OnEnvironment(pos, ent.num, raid, ent.IgnoreClasses) --ignoreClasses so the check won't check if the ent is in an environment that exists out of the certain ent
	if onplanet then
	--if envr then
		local valid, planet, plapos , ig, gravity, habitat, air, co2, n, atmosphere, pressure,  ltemperature, stemperature, sunburn = SB_Get_Environment_Info(num)
		if pos:Distance(plapos) > ig then
			--ent:SetGravity(0.00001)
			if (!ent:IsPlayer()) then
				ent:GetPhysicsObject():ApplyForceCenter((plapos-ent:GetPos())*(ent:GetPhysicsObject( ):GetMass()*mult))
			else
				if nonoclip == "0" and ent:GetMoveType() == MOVETYPE_NOCLIP then return end
				vec = (plapos-ent:GetPos())*(1*mult)
				vec2 = ent:GetVelocity()
				ent:SetVelocity( (vec)  )
			end
		else
			ent:SetGravity(1)
			local phys = ent:GetPhysicsObject()
			phys:EnableGravity( true )
			phys:EnableDrag( true )
		end
	--else
		--ent:SetGravity(1)
	end
end]]


--[[
function throwit2(ent, override, enti)
	--function for custom sents
  if override == true then
	mult = tostring(GetConVarNumber("sb_gravmul"))
	raid = tostring(GetConVarNumber("sb_rad"))
	nonoclip = tostring(GetConVarNumber("sb_affectnoclip"))
	nograv = tostring(GetConVarNumber("sb_disablegrav"))
	if not ent:IsValid() 
	or not ent:GetPhysicsObject():IsValid() 
	or ent:GetPhysicsObject():IsAsleep()
	 
	then return end
	local pos = ent:GetPos()
	local envr
	local plapos
	local ig
	for no, env in pairs(enti) do
		if pos:Distance(env.ent:GetPos()) < (env.rad + env.ent.erad) then
			envr = env
			plapos = env.ent:GetPos()
			ig = env.rad
			mult = env.ent.mul
			
		end
	end
	--local onplanet, num = SB_OnEnvironment(pos, ent.num, raid, ent.IgnoreClasses) --ignoreClasses so the check won't check if the ent is in an environment that exists out of the certain ent
	--if onplanet then
	if envr then
		--local valid, planet, plapos , ig, gravity, habitat, air, co2, n, atmosphere, pressure,  ltemperature, stemperature, sunburn = SB_Get_Environment_Info(num)
		if pos:Distance(plapos) > ig then
			if nograv == "1" then
			ent:SetGravity(0.00001)
						local phys = ent:GetPhysicsObject()
			phys:EnableGravity( false )
			phys:EnableDrag( false )
			end
			if (!ent:IsPlayer()) then
				ent:GetPhysicsObject():ApplyForceCenter((plapos-ent:GetPos())*(ent:GetPhysicsObject( ):GetMass()*mult))
			else
				if nonoclip == "0" and ent:GetMoveType() == MOVETYPE_NOCLIP then return end
				vec = (plapos-ent:GetPos())*(1*mult)
				vec2 = ent:GetVelocity()
				ent:SetVelocity( (vec)  )
			end
		else
			ent:SetGravity(1)
						local phys = ent:GetPhysicsObject()
			phys:EnableGravity( true )
			phys:EnableDrag( true )
		end
	else
		ent:SetGravity(1)
					local phys = ent:GetPhysicsObject()
			phys:EnableGravity( true )
			phys:EnableDrag( true )
	end

	return
  end
  
	mult = tostring(GetConVarNumber("sb_gravmul"))
	raid = tostring(GetConVarNumber("sb_rad"))
	nonoclip = tostring(GetConVarNumber("sb_affectnoclip"))
	nograv = tostring(GetConVarNumber("sb_disablegrav"))
	if not ent:IsValid() 
	or not ent:GetPhysicsObject():IsValid() 
	or ent:GetPhysicsObject():IsAsleep()
	 
	then return end
	local pos = ent:GetPos()
	local envr
	local plapos
	local ig
	for no, env in pairs(envs) do
		if pos:Distance(env.ent:GetPos()) < (env.rad + raid) then
			envr = env
			plapos = env.ent:GetPos()
			ig = env.rad
		end
	end
	--local onplanet, num = SB_OnEnvironment(pos, ent.num, raid, ent.IgnoreClasses) --ignoreClasses so the check won't check if the ent is in an environment that exists out of the certain ent
	--if onplanet then
	if envr then
		--local valid, planet, plapos , ig, gravity, habitat, air, co2, n, atmosphere, pressure,  ltemperature, stemperature, sunburn = SB_Get_Environment_Info(num)
		if pos:Distance(plapos) > ig  then
			if nograv == "1" then
			ent:SetGravity(0.00001)
			local phys = ent:GetPhysicsObject()
			phys:EnableGravity( false )
			phys:EnableDrag( false )
			end
			if (!ent:IsPlayer()) then
				ent:GetPhysicsObject():ApplyForceCenter((plapos-ent:GetPos())*(ent:GetPhysicsObject( ):GetMass()*mult))
			else
				if nonoclip == "0" and ent:GetMoveType() == MOVETYPE_NOCLIP then return end
				vec = (plapos-ent:GetPos())*(1*mult)
				vec2 = ent:GetVelocity()
				ent:SetVelocity( (vec)  )
			end
		else
			ent:SetGravity(1)
			local phys = ent:GetPhysicsObject()
			phys:EnableGravity( true )
			phys:EnableDrag( true )
		end
	else
		ent:SetGravity(1)
					local phys = ent:GetPhysicsObject()
			phys:EnableGravity( true )
			phys:EnableDrag( true )
	end
end]]

--[[function throwit3(ent)
	mult = tostring(GetConVarNumber("sb_gravmul"))
	raid = tostring(GetConVarNumber("sb_rad"))
	nonoclip = tostring(GetConVarNumber("sb_affectnoclip"))
	nograv = tostring(GetConVarNumber("sb_disablegrav"))
	EVS = GAMEMODE:GetEnvironments()
	
	if not ent:IsValid() 
	or not ent:GetPhysicsObject():IsValid() 
	or ent:GetPhysicsObject():IsAsleep()
	 
	then return end
	--local pos = ent:GetPos()
	--local onplanet, num = SB_OnEnvironment(pos, ent.num, raid, ent.IgnoreClasses) --ignoreClasses so the check won't check if the ent is in an environment that exists out of the certain ent
	local pos = ent:GetPos()
	local onplanet
	local plapos
	local ig
	for no, env in pairs(EVS) do
		if pos:Distance(env:GetPos()) < (env:GetSize() + raid) then
			envr = env
			plapos = env:GetPos()
			ig = env:GetSize()
			onplanet = true --depreciated
		end
	end
	if onplanet then
	--if envr then
		--local valid, planet, plapos , ig, gravity, habitat, air, co2, n, atmosphere, pressure,  ltemperature, stemperature, sunburn = SB_Get_Environment_Info(num)
		if pos:Distance(plapos) > ig then
			--ent:SetGravity(0.00001)
			if (!ent:IsPlayer()) then
				ent:GetPhysicsObject():ApplyForceCenter((plapos-ent:GetPos())*(ent:GetPhysicsObject( ):GetMass()*mult))
			else
				if nonoclip == "0" and ent:GetMoveType() == MOVETYPE_NOCLIP then return end
				vec = (plapos-ent:GetPos())*(1*mult)
				vec2 = ent:GetVelocity()
				ent:SetVelocity( (vec)  )
			end
		else
			ent:SetGravity(1)
			local phys = ent:GetPhysicsObject()
			phys:EnableGravity( true )
			phys:EnableDrag( true )
		end
	--else
		--ent:SetGravity(1)
	end
end]]

local function allowPush( ply, ent )
	local hasCPPI = (type( CPPI ) == "table")
	local hasEPS = type( eps ) == "table"
	local hasPropSecure = type( PropSecure ) == "table"
	local hasProtector = type( Protector ) == "table"
	
	if not hasCPPI and not hasPropProtection and not hasSPropProtection and not hasEPS and not hasPropSecure and not hasProtector then return true end
	
	local t = hook.GetTable()
	
	local fn = t.CanTool.PropProtection
	hasPropProtection = type( fn ) == "function"
	if hasPropProtection then
		-- We're going to get the function we need now. It's local so this is a bit dirty			
		local gi = debug.getinfo( fn )
		for i=1, gi.nups do
			local k, v = debug.getupvalue( fn, i )
			if k == "Appartient" then
				propProtectionFn = v
			end
		end
	end
	
	local fn = t.CanTool[ "SPropProtection.EntityRemoved" ]	
	hasSPropProtection = type( fn ) == "function"
	if hasSPropProtection then
		local gi = debug.getinfo( fn )
		for i=1, gi.nups do
			local k, v = debug.getupvalue( fn, i )
			if k == "SPropProtection" then
				SPropProtectionFn = v.PlayerCanTouch
			end
		end
	end
	
	local owns
	if hasCPPI then
		owns = ent:CPPICanPhysgun( ply )
	elseif hasPropProtection then -- Chaussette's Prop Protection (preferred over PropSecure)
		owns = propProtectionFn( ply, ent )
	elseif hasSPropProtection then -- Simple Prop Protection by Spacetech
		if ent:GetNetworkedString( "Owner" ) ~= "" then -- So it doesn't give an unowned prop
 			owns = SPropProtectionFn( ply, ent )
		else
			owns = false
 		end
 	elseif hasEPS then -- EPS
 		owns = eps.CanPlayerTouch( ply, ent )
	elseif hasPropSecure then -- PropSecure
		owns = PropSecure.IsPlayers( ply, ent )
	elseif hasProtector then -- Protector
		owns = Protector.Owner( ent ) == ply:UniqueID()
	end
	
	return owns
end

--Added Revision v1.1
--This function is internal and has no error checks, careful...
local function doPush(Entity, Gravity, posTocenter, totalRad, nonaffectRadius, affectPlayers, affectNoclipped)

	--Perform checks, make sure we are in the desired environment to continue
	--if not Entity:IsValid() or not Entity:GetPhysicsObject():IsValid() or Entity:GetPhysicsObject():IsAsleep() --[[Is it frozen?]] then return end --Don't do anything
	if Entity:IsPlayer() and not affectPlayers then return end --allowed to touch players?
	if (Entity:GetMoveType() == MOVETYPE_NOCLIP) and not affectNoclipped then return end --allowed to touch noclipped?
	
	local entityPos 		= Entity:GetPos()
	local totalDistance		= entityPos:Distance( posTocenter )
	local estimatedForceMul	= (Gravity * (1 - ((totalDistance - nonaffectRadius) / totalRad))) --Beta distance gravity decay

	if Entity:IsPlayer() then
		--Msg("Mul: " .. estimatedForceMul .. "\n")
		--Msg("Mul %: " .. (1 - ((totalDistance - nonaffectRadius) / totalRad)) .. "\n")
		local forceVector = (posTocenter - entityPos) * estimatedForceMul
		Entity:SetVelocity( forceVector )
	else
		local physObj = Entity:GetPhysicsObject()
		local forceVector = (posTocenter - entityPos) * (physObj:GetMass() * estimatedForceMul)
		physObj:ApplyForceCenter( forceVector )
	end
	
end

local function performUpdate()

	local tickRate = tonumber(GetConVarNumber("sb_updatera"))
	local nextUpdate = 0

	if CurTime() < nextUpdate then return end

		local Gravity 		= tonumber(GetConVarNumber("sb_gravmul"))
		local affectRadius 	= tonumber(GetConVarNumber("sb_rad"))
		local touchNoclip 	= tonumber(GetConVarNumber("sb_affectnoclip")) == 1
		local disableGravity = tonumber(GetConVarNumber("sb_disablegrav")) == 1
		local entList = ents.GetAll( )
		
		--Temporarly disabled...
		
		local cents = {}
		--local over = false
		local orbitEnts = ents.FindByClass( "orbit" )
		local environments = ents.FindByClass( "Environment" )
		local planetcount = table.Count(environments)
		
		for _, ent in ipairs( entList ) do
			if not ent:IsValid() 
			or not ent:GetPhysicsObject():IsValid() 
			or ent:GetPhysicsObject():IsAsleep() then
			else
				if ent.defgrav then
				//	ent:SetGravity(1)
				//	local phys = ent:GetPhysicsObject()
				//	phys:EnableGravity( true )
				//	phys:EnableDrag( true )
					ent.defgrav = false
				end
				local entityPos = ent:GetPos()
				--Load Environments compatability
				if planetcount>=1 then
					for _, v in pairs(environments) do
						local environPos = v.ent:GetPos()
						local totalDistance = entityPos:Distance(environPos)
						if (totalDistance > v:GetSize()) and (totalDistance < (v:GetSize + affectRadius)) then
							doPush(ent, Gravity * 0.5, environPos, affectRadius, v.rad, true, touchNoclip)
						end
					end
				--No spacebuild found
				else
					for _, v in pairs(envs) do
						local environPos = v.ent:GetPos()
						local totalDistance = entityPos:Distance(environPos)
						if (totalDistance > v.rad) and (totalDistance < (v.rad + affectRadius)) then
							if disableGravity then
								ent.defgrav = true
								//ent:SetGravity(0.00001)
								//local phys = ent:GetPhysicsObject()
								//phys:EnableGravity( false )
								//phys:EnableDrag( false )								
								--local phys = ent:GetPhysicsObject()
							end
							doPush(ent, Gravity * 0.5, environPos, affectRadius, v.rad, true, touchNoclip)
						end
					end
				end
				

				for _, v in pairs(orbitEnts) do
					if not (v == ent) and (allowPush(v.OwnerM, ent) or v.OwnerM == ent) then
						local centPos = v:GetPos()
						if v:IsValid() then
							if (entityPos:Distance(centPos) > v.rad) and (entityPos:Distance(centPos) < (v.rad + v.erad)) then
								if disableGravity then
									ent.defgrav = true
									//ent:SetGravity(0.00001)
									//local phys = ent:GetPhysicsObject()
									//phys:EnableGravity( false )
									//phys:EnableDrag( false )								
									--local phys = ent:GetPhysicsObject()
								end
								doPush(ent, v.mul, centPos, v.erad, v.rad, true, touchNoclip)
							elseif ent.defgrav then
								--ent:SetGravity(1)
								--local phys = ent:GetPhysicsObject()
								--phys:EnableGravity( true )
								--phys:EnableDrag( true )
							end
						end
					end
				end
				--Depreciated
				--[[
				if over == true then
					throwit2(ent, over, cents)
				end]]
			end
		end

	nextUpdate = CurTime() + tickRate

end
hook.Add("Think", "Gravity_Push", performUpdate)